import { setInterval, clearInterval } from "timers";
import { IGlobal, TimeUtils } from "../../Index";

const schedule = require('node-schedule');
declare var global: IGlobal;
export abstract class ScheduleBase {
    private _isStart: boolean = false;
    abstract get config(): IScheduleConfig;
    protected abstract async mExecute();

    private _scheduleObj: any;
    private _timer: any;
    public async start() {
        if (this._isStart) return;
        if (this.config.close) return;
        this._isStart = true;
        if (this.config.cron) {
            this._scheduleObj = schedule.scheduleJob(this.config.cron, this.execute.bind(this));
        } else if (this.config.interval) {
            let intervalTime = TimeUtils.timeStrToNumber(this.config.interval);
            if (intervalTime > 0) {
                this._timer = setInterval(this.execute.bind(this), intervalTime * 1000);
            }
        }
        if (this.config.justRun) {
            await this.execute();
        }
    }

    public async execute() {
        if (this.config.master && !global.config.bMaster) return;
        try {
            await this.mExecute();
            this.log.debug("计划任务执行[" + this.constructor.name + "]");
        } catch (e) {
            //todo 记录日志 this.constructor.name
            this.log.error("计划任务出错[" + this.constructor.name + "]\n" + e.message);
        }
    }

    public stop() {
        if (!this._isStart) return;
        this._isStart = false;
        if (this._timer) {
            clearInterval(this._timer);
            this._timer = null;
        }
        if (this._scheduleObj) {
            this._scheduleObj.cancel();
            this._scheduleObj = null;
        }
    }

    public get log() {
        return global.log;
    }
}

export interface IScheduleConfig {
    interval?: string,                //执行间隔  秒"1s",分钟"1m",小时"1h",天"1d"
    cron?: string,                    //cron风格配置
    type?: string                     //预留字段
    justRun?: boolean                  //启动运行一次
    close?: boolean                       //是否不启动
    master?: boolean                     //只有主进程运行，默认false
}

// *  *  *  *  *  *                                                 允许的特殊字符  
// ┬  ┬  ┬  ┬  ┬  ┬
// │  │  │  │  │  |
// │  │  │  │  │  └ day of week (0 - 7) (0 or 7 is Sun)                 , - * ? / L C # 
// │  │  │  │  └───── month (1 - 12)                                     , - * / 
// │  │  │  └────────── day of month (1 - 31)                           , - * ? / L W C 
// │  │  └─────────────── hour (0 - 23)                                 , - * /  
// │  └──────────────────── minute (0 - 59)                             , - * / 
// └───────────────────────── second (0 - 59, OPTIONAL)                 , - * / 
// “?”字符：表示不确定的值

// “,”字符：指定数个值

// “-”字符：指定一个值的范围

// “/”字符：指定一个值的增加幅度。n/m表示从n开始，每次增加m

// “L”字符：用在日表示一个月中的最后一天，用在周表示该月最后一个星期X

// “W”字符：指定离给定日期最近的工作日(周一到周五)

// “#”字符：表示该月第几个周X。6#3表示该月第3个周五

//示例
// 每隔5秒执行一次：*/5 * * * * ?

// 每隔1分钟执行一次：0 */1 * * * ?

// 每天23点执行一次：0 0 23 * * ?

// 每天凌晨1点执行一次：0 0 1 * * ?

// 每月1号凌晨1点执行一次：0 0 1 1 * ?

// 每月最后一天23点执行一次：0 0 23 L * ?

// 每周星期天凌晨1点实行一次：0 0 1 ? * L

// 在26分、29分、33分执行一次：0 26,29,33 * * * ?

// 每天的0点、13点、18点、21点都执行一次：0 0 0,13,18,21 * * ?